/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package kuti.grp5;

import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
import kuti.*;

/**
 *
 * @author Pierre & Jonathan
 */
public class Radar implements IRadar{
    
    public double maxRadarLenght;

    private long lastUpdateStep;
    
    private IObservableLawn radarLawnInfo = null;
    
    private Map<IObservable, Double> radarElements = new Hashtable<IObservable, Double>();
    private ISimulParams simulParams;
    private Line2D radar;
    
    private Random random = new Random();
    
    
    public Radar(ISimulParams simulParams){
        
        int a =  SimulParams.WORLD_HEIGHT * SimulParams.WORLD_HEIGHT;
        int b = SimulParams.WORLD_WIDTH * SimulParams.WORLD_WIDTH;
        maxRadarLenght = Math.sqrt(a + b);
        
        this.simulParams = simulParams;
        
        
    }
    
    public Line2D getRadarLine(){
        return radar;
    }
    
    @Override
    public IObservableLawn getRadarLawnInfo() {
        return radarLawnInfo;
    }

    /**
     * This method returns a collection of all charging stations, kutis, 
     * obstacles and magnectic obstacles located on the trajectory of the radar
     * 
     * @return Returns a collection of all charging stations, kutis, obstacles
     * and magnectic obstacles located on the trajectory of the radar
     */
    
    @Override
    public Map<IObservable, Double> getRadarElements() {
        return radarElements;
    }

    @Override
    public long getLastUpdateStep() {
        return lastUpdateStep;
    }
    
    /**
     * For each element located on the trajectory of the radar, the sensor 
     * returns information about the type of the element and the distance 
     * from the center of the kuti.
     * 
     * If the element is a :
     * - charging station, the distance from the nearest point on the 
     *   trajectory and the factor τ that characterizes the rated terminal
     * - kuti, the distance from the nearest point and level of energy
     * - obstacle, the distance to the intersection point
     * - magnetic obstacle, the distance to the intersection point
     * 
     * @param kuti  The current Kuti
     * @param wm    The world manager
     * @param step  The current step number
     * 
     */
    
    public void updateRadar(IKuti kuti, IWorldManager wm, long step){
        
        // Define start and stop point of the radar
        Point2D startRadar = kuti.getCenterPosition();
        Point2D endRadar = KutiTrajectory.moveTo(startRadar, maxRadarLenght, kuti.getOrientation());
        
        // Create a line with the points
        radar = new Line2D.Double(startRadar, endRadar);
        
        // Create the datas from the previous measurement 
        radarElements.clear();
        
        // Check if the charging station is intersects with the radar
        for(IChargingStation ics : wm.getAllChargingStation()){
            
            // Add the charging station to the radar elements if necessary
            checkElementOfRadar((IRadarElement) ics, radar);
            
        }
        
        // Check if the obstacle is intersects with the radar
        for(IObstacle io : wm.getAllObstacle()){
            
            // Add the obstacle to the radar elements if necessary
            checkElementOfRadar((IRadarElement) io, radar);
            
        }
        
        // Check if the obstacle is intersects with the radar
        for(IKuti ik : wm.getAllKuti()){
            
            if(ik != kuti){
                
                // Add the kuti to the radar elements if necessary
                checkElementOfRadar((IRadarElement) ik, radar);
            
            }
            
        }
        
        lastUpdateStep = step;
        
        // Update the lawn height
        radarLawnInfo = new ObservableLawn(kuti, radar, (Lawn) wm.getLawn());
        
        
    }
    
    public void checkElementOfRadar(IRadarElement element, Line2D radar){
        
        // Check if the element intersects with the radar line
        if(element.isIntersects(radar)){
            
            // Calculate the exact distance to the element
            double distance = element.intersectsDistance(radar);
            
            // Create a nose
            distance = noise(distance);
            
            // Add the element to the radar elements
            radarElements.put(element, Math.abs(distance));
            
        }
        
    }
    
    private double noise(double distance){
        
        // Get the radar noise factor
        double factor = simulParams.getRadarNoiseFactor();
        
        // Generate the noise
        double noise = random.nextDouble() * distance * factor;
        
        if(random.nextBoolean()){
            // Add to the distance
            distance -= noise;
        }else{
            // Sub to the distance
            distance += noise;
        }
        
        
        return distance;
    }
        
}
